package com.pks.datacenter.aspect;

import io.swagger.annotations.Api;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.ohedu.base.model.UserModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.pks.datacenter.common.WebContext;
import com.pks.datacenter.config.RequestHolder;
import com.pks.datacenter.entity.basic.OperLog;
import com.pks.datacenter.service.basic.OperLogService;
import com.pks.datacenter.utils.SUtilClass;
import com.pks.resultful.common.SRemoteResult;
import com.pks.util.UtilConvert;
import com.pks.util.coder.database.DBField;
 
/**
 * 操作日志切面定义
 */
@Aspect
@Component
public class LogApsect {
    
    @SuppressWarnings("unused")
	private static Logger logger = LoggerFactory.getLogger(LogApsect.class);
    
//    private long currentTime = 0L;

    @Pointcut("@annotation(com.pks.datacenter.aspect.AspectLogTag)")
    public void logPointcut() {
        
    }
    
    @Autowired
    private OperLogService operLogService;
    

    /**
     *  配置环绕通知
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @SuppressWarnings("rawtypes")
	@Around("logPointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
    	try {
    		Object result;
    		Long currentTime = System.currentTimeMillis();
    		result = joinPoint.proceed();
    		OperLog log = new OperLog("INFO", System.currentTimeMillis() - currentTime);
    		SRemoteResult sr = (SRemoteResult) result;
    		save(joinPoint,log,sr);
    		return sr;
		} catch (Exception e) {
			e.printStackTrace();
		}
    	return null;
    }

    @SuppressWarnings("rawtypes")
	private void save(ProceedingJoinPoint joinPoint,OperLog log,SRemoteResult sr) {
    	try {
    		HttpServletRequest request = RequestHolder.getHttpServletRequest();
        	UserModel logined = WebContext.getLoginUser(request);
            if (log == null) log = new OperLog();
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Api api = joinPoint.getTarget().getClass().getAnnotation(Api.class);
            
            Method method = signature.getMethod();
            AspectLogTag aopLog =  method.getAnnotation(AspectLogTag.class);
            List<String> saveParams = new ArrayList<String>();
            List<String> excludeParams = new ArrayList<String>();
            List<String> objParams = new ArrayList<String>();
            if (aopLog.params() != null && aopLog.params().length > 0) {
    			saveParams = Arrays.asList(aopLog.params());
    		}
            if (aopLog.objParams() != null && aopLog.objParams().length > 0) {
            	objParams = Arrays.asList(aopLog.objParams());
    		}
            if (aopLog.excludeParams() != null && aopLog.excludeParams().length > 0) {
            	excludeParams = Arrays.asList(aopLog.excludeParams());
    		}
            // 方法路径
            String methodName = joinPoint.getTarget().getClass().getName()+"."+signature.getName()+"()";
//            StringBuilder params = new StringBuilder("{");
            Map<String, Object> paramsMap = new HashMap<String, Object>();
            // 参数值
            Object[] argValues = joinPoint.getArgs();
            // 参数名称
            String[] argNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames();
//            Class[] parameterTypes = ((MethodSignature)joinPoint.getSignature()).getParameterTypes();
            if (argValues != null){
                for (int i = 0; i < argValues.length; i++) {
                	String paramName = argNames[i];
//                	Class paramType = parameterTypes[i];
                	if (argValues[i] instanceof HttpServletRequest || argValues[i] instanceof HttpServletResponse) {
                		continue;
                	}
                	if (argValues[i] == null) {
						continue;
					}
                	if (argValues[i].getClass().getName().startsWith("java.") || argValues[i].getClass().getName().startsWith("javax.")) {
                		if (excludeParams.contains(paramName)) {
    						continue;
    					}
            			paramsMap.put(paramName, argValues[i]);
                	} else {
                		Map<String, Object> objMap = JSON.parseObject(JSON.toJSONString(argValues[i]), new TypeReference<Map<String, Object>>() {});
            			for (Map.Entry<String, Object> entry : objMap.entrySet()) {
        					if (excludeParams.contains(entry.getKey())) {
        						continue;
        					}
        					paramsMap.put(entry.getKey(), entry.getValue());
        		        }
                	}
                	
//                	if (!argNames[i].equals("request") && !argNames[i].equals("response")) {
//                		if (objParams.contains(paramName)) {
//                			Map<String, Object> objMap = JSON.parseObject(JSON.toJSONString(argValues[i]), new TypeReference<Map<String, Object>>() {});
//                			for (Map.Entry<String, Object> entry : objMap.entrySet()) {
//            					if (excludeParams.contains(entry.getKey())) {
//            						continue;
//            					}
//            					paramsMap.put(entry.getKey(), entry.getValue());
//            		        }
//                		} else {
//                			if (excludeParams.contains(paramName)) {
//        						continue;
//        					}
//                			paramsMap.put(paramName, argValues[i]);
//                		}
//                	}
                	
//                	if (saveParams.size() > 0) {
//                		if (saveParams.contains(argNames[i])) {
//                			paramsMap.put(argNames[i], argValues[i]);
////                			params.append(" ").append(argNames[i]).append(": ").append(argValues[i]);    
//    					}
//                	} else {
//    	            	if (!argNames[i].equals("request") && !argNames[i].equals("response")) {
//    	            		if (argValues[i] != null) {
//    	            			if ("obj".equals(argNames[i])) {
//    	            				Map<String, Object> objMap = JSON.parseObject(JSON.toJSONString(argValues[i]), new TypeReference<Map<String, Object>>() {});
//    	            				paramsMap.putAll(objMap);
//    	            			} else {
//    	            				paramsMap.put(argNames[i], argValues[i]);
//    	            			}
////                				params.append(" ").append(argNames[i]).append(": ").append(argValues[i]);            			
//    	            		}
//    	            	}
//                	}
                }
            }
//            System.err.println(JSON.toJSONString(paramsMap));
            log.setOperType(aopLog.operType());
            if (methodName.endsWith("modify()")) {
    			if (!paramsMap.containsKey("id")) {
    				log.setOperType("新增");
    			}
    		}
            log.setOperModule(UtilConvert.array2String(api.tags()));
            log.setMethodName(methodName);
            log.setParams(JSON.toJSONString(paramsMap));
            // 操作模块
            log.setRequestIp(WebContext.getRealIpAddress(request));
            if (logined != null) {
    	        log.setUserId(logined.getId());
    	        log.setUserName(logined==null?"":logined.getRealName());
            }
            if (sr.success()) {
            	log.setOperResult(1);
            } else {
            	log.setOperResult(0);
            	log.setOperResultMsg(sr.getMsg());
            }
            log.setRequestUrl(request.getRequestURL().toString());
            log.insertBefore();
            
            if (StringUtils.isNotBlank(log.getParams()) && log.getParams().length() > 2000) {
            	log.setParams(log.getParams().substring(0, 2000));
            }
            if (StringUtils.isNotBlank(log.getContent()) && log.getContent().length() > 2000) {
            	log.setContent(log.getContent().substring(0, 2000));
            }
            operLogService.insert(log);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
    
    
	

//	  /**
//     *  配置异常通知
//     * @param joinPoint
//     * @param e
//     */
//    @AfterThrowing(pointcut = "logPointcut()",throwing = "e")
//    public void logAfterThrowing(JoinPoint joinPoint,Throwable e){
//       SystemOperLog log = new SystemOperLog("ERROR",System.currentTimeMillis() - currentTime);
//       log.setExceptionDetail(ThrowableUtil.stackTraceToString(e.getClass().getName(),e.getMessage(),e.getStackTrace()));
//       HttpServletRequest request = RequestHolder.getHttpServletRequest();
//       xtLogService.save(getUsername(),StringUtils.getBrowser(request),StringUtils.getIp(request),request.getRequestURI(), (ProceedingJoinPoint) joinPoint,log);
//    }

 
    
}
 